DES加密算法原理及Python代码实现 |
您所在的位置:网站首页 › 秘钥和密钥 读音 › DES加密算法原理及Python代码实现 |
写在前面: 1、本文中DES加解密基本流程及S盒等参数参照自杨波《现代密码学(第四版)》,实现过程均为自编函数。 2、为了说明64bit密钥中,只有56bit真正参与加解密过程,对网上代码中的密钥生成过程做出了修改,详见正文。 3、本文借鉴了网上部分代码,具体见参考文献,并对部分地方按题主想法进行了优化修改。 1. DES算法理论介绍具体可参见杨波《现代密码学(第四版)》。本文只做简要介绍。 1.1 DES介绍DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。 1.2 DES加解密算法描述![]() 图1.2是DES加密变换框图,其中明文一组为64bit,密钥K长度56bit。加密过程有3个阶段: 1、初始置换IP,用于重排明文分组的64比特数据。 2、经过具有相同功能的16轮Feistel变换,每轮中F函数中都有置换和代换运算,第16轮变换的输出分为左右两半,并被交换次序。 3、经过一个逆初始置换IP-1(为IP的逆)从而产生64比特的密文。 1.2.1 轮结构采用Feistel相同的轮结构,将64bit的轮输入分为32bit的左、右两半,分别记为L和R: L i = R i − 1 L_i=R_{i-1} Li=Ri−1 R i = L i − 1 ⊕ F ( R i − 1 , K i ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R_i=L_{i-1}\oplus F\left( R_{i-1},K_i \right) Ri=Li−1⊕F(Ri−1,Ki) 其中,F函数示意图见图1.2.1。 ![]() ![]() 图1.2.2是使用56比特密钥的方法。密钥首先通过一个置换函数PC_1,然后,对加密过程的每一轮,通过一个左循环移位和一个置换PC_2产生一个子密钥。其中每轮的置换都相同,但由于密钥被重复迭代,所以产生的每轮子密钥不相同。 1.2.3 DES解密和Feistel密码一样,DES的解密和加密使用同一种算法,但子密钥使用的顺序相反。 2. Python代码实现 2.1 实现思路由于加密与解密算法类似,此处给出加密算法实现思路: Step1:从文件中读取明文; Step2:将明文利用ASCII换成01比特流; Step3:将明文比特流每64位分为一组,最后不足的用0补齐; Step4:对64位比特加密操作(进行IP置换,16轮的Feistel变换、交换L、R、IP逆置换,将L、R合并为密文比特流); Step5:将每一组密文比特流合并转换成密文字符保存至文件。 2.2 模块化程序设计 2.2.1 各个模块调用关系及实现功能设计![]() 根据2.1中的实现思路,DES加解密算法各个模块调用关系及实现功能设计如图2.2.1所示,2.2.2中将详细介绍各个功能的代码实现。 2.2.2 模块功能实现针对2.2.1的实现思路,分析DES加解密算法流程,可将其具体分成不同的模块分别设计: 1.)文件读入模块 def read_file(filename): ''' filename : 打开文件名 return : 读取文件中字符串 ''' try: fp = open(filename,"r",encoding='utf-8') message = fp.read() fp.close() return message except: print("Open file error!")2.)文件写入模块 将字符串写入文件text.txt与文件读入代码类似,只做如下修改: fp = open('text.txt','w',encoding='utf-8') fp.write(message)def write_file(message): 输入需要写入字符串,即可生成含有该字符串的text.txt文件。 3.)字符串转01比特流 def str_bit( message ): ''' message :字符串 return :将读入的字符串序列转化成01比特流序列 ''' bits = "" for i in message: asc2i = bin(ord(i))[2:] #bin将十进制数转二进制返回带有0b的01字符串 '''为了统一每一个字符的01bit串位数相同,将每一个均补齐8位''' for j in range(8-len(asc2i)): asc2i = '0' + asc2i bits += asc2i return bits每一个字符利用ord( )函数转化成对应ASCII值,利用bin( )将其转换成二进制字符串。 4.)01比特流转字符 def bit_str(bits): 输入01比特串(长度要是8的倍数),返回对应的字符,核心代码如下,主要利用int( )和chr( )函数。 for i in range(len(bits)//8): temp += chr(int(bits[i*8:(i+1)*8],2))5.)密钥字符串转比特流 本文假定密钥比特流的8、16、24、32、40、48、56、64位采用偶校验方式,分别校验其前面的7位01串。密钥字符串依然采用ASCII编码方式,一个字符占7位,第8位采用偶校验方式,核心代码如下: def process_key(key): ''' key : 输入的密钥字符串 return : 64bit 01序列密钥(采用偶校验的方法) ''' key_bits = "" for i in key: count = 0 asc2i = bin(ord(i))[2:] '''将每一个ascii均补齐7位,第8位作为奇偶效验位''' for j in asc2i: count += int(j) if count % 2 == 0: asc2i += '0' else: asc2i += '1' for j in range(7-len(asc2i)): asc2i = '0' + asc2i key_bits += asc2i if len(key_bits) > 64: return key_bits[0:64] else: for i in range(64-len(key_bits)): key_bits += '0' return key_bits6.)对比特流分组 函数定义如下,最后一组位数不足即补0。实现简单,此处不在赘述。 def divide(bits,bit): ''' bits : 将01bit按bit一组进行分组 return : 按bit位分组后得到的列表 '''7.)IP置换 为了实现简单,提前将IP、IP_RE、PC_1、PC_2、E、P、S等盒值写入文件DES_BOX.py,主函数即可直接调用。IP置换实现如下: def IP_change(bits): ''' bits:一组64位的01比特字符串 return:初始置换IP后64bit01序列 ''' ip_str = "" for i in IP: ip_str = ip_str + bits[i-1] return ip_str8.)PC_1置换 实现代码同IP置换,此处不在赘述。 9.)比特串左移 def key_leftshift(key_str,num): 将输入的01比特流key_str循环左移num位返回,实现过于简单,此处不在赘述。 10.)PC_2置换 实现代码同IP置换,此处不在赘述。 11.)16轮密钥生成 def generate_key(key): ''' key : 64bit01密钥序列 return : 16轮的16个48bit01密钥列表按1-16顺序 ''' key_list = ["" for i in range(16)] key = PC_1_change(key) #1、调用置换PC_1 key_left = key[0:28] #2、左右28位分开 key_right = key[28:] for i in range(len(SHIFT)): #共16轮即16次左循环移位 key_left = key_leftshift(key_left, SHIFT[i]) #3、调用比特串左移函数 key_right = key_leftshift(key_right, SHIFT[i]) key_i = PC_2_change(key_left + key_right) #4、左右合并调用置换PC_2 key_list[i] = key_i #5、将每一轮的56bit密钥存入列表key_list return key_list12.)E置换 实现代码同IP置换,此处不在赘述。 13.)异或运算 函数实现较为简单,将输入的两个字符串逐位运算即可,仅给出定义如下。 def xor(bits,ki): ''' bits : 48bit01字符串 / 32bit01 F函数输出 ki : 48bit01密钥序列 / 32bit01 Li return :bits与ki异或运算得到的48bit01 / 32bit01 '''14.)单次S盒查找 def s(bits,i): ''' bits : 6 bit01字符串 i : 使用第i个s盒 return : 4 bit01字符串 ''' row = int(bits[0]+bits[5],2) col = int(bits[1:5],2) num = bin(S[i-1][row*16+col])[2:] #i-1号S盒的row*16+col号数 for i in range(4-len(num)): #补齐4位后输出 num = '0'+num return num15.)S盒变换 def S_change(bits): 输入48bit字符串,输出经过S盒之后的32bit字符串。核心代码如下,调用8次单次S盒查找函数: for i in range(8): temp = bits[i*6:(i+1)*6] temp = s(temp,i+1) s_change += temp16.)P置换 实现代码同IP置换,此处不在赘述。 17.)F函数 通过调用12-16模块即可实现第 i i i轮F函数运算: def F(bits,ki): ''' bits : 32bit 01 Ri输入 ki : 48bit 第i轮密钥 return : F函数输出32bit 01序列串 ''' bits = xor(E_change(bits),ki) bits = P_change(S_change(bits)) return bits18.)IP逆置换 实现代码同IP置换,此处不在赘述。 19.)64bit加密 调用IP置换、16轮密钥生成、F函数、异或运算、IP逆置换等模块可以实现64bit一组明文的加密: def des_encrypt(bits,key): ''' bits : 分组64bit 01明文字符串 key : 64bit01密钥 return : 加密得到64bit 01密文序列 ''' bits = IP_change(bits) # IP置换 L = bits[0:32] # 切片分成两个32bit R = bits[32:] key_list = generate_key(key) # 生成16个密钥 for i in range(16): # 16轮迭代变换 L_next = R R = xor(L,F(R,key_list[i])) L = L_next result = IP_RE_change( R + L) # IP逆置换 return result20.)64bit解密 def des_decrypt(bits,key):该模块与64bit加密模块流程相同,不同在于16个密钥使用顺序相反,16轮代换代码如下,其余代码同加密。 for i in range(16): L_next = R R = xor(L,F(R,key_list[15-i])) L = L_next21.)整体加密模块 def all_des_encrypt(message,key): 读入明文字符串message,以及密钥字符串key,返回加密后01比特流。通过调用字符串转01比特流、密钥字符串转比特流、对比特流分组、64bit加密等模块即可实现: def all_des_encrypt(message,key): ''' message : 读入明文字符串 key : 读入密钥串 returns : 密文01序列 ''' message = str_bit(message) # 明文转01比特流 key = process_key(key) # 64bit初始密钥生成 mess_div = divide(message, 64) # 明文按64bit一组进行分组 result ="" for i in mess_div: result += des_encrypt(i, key) #对每一组进行加密运算 return result22.)整体解密模块 def all_des_decrypt(message,key): 读入明文字符串message,以及密钥字符串key,返回解密后01比特流。与加密类似,此处不在赘述。 2.2.3 主模块输出提示语,并与用户交互。通过调用文件读入或写入、字符串转01比特流、比特流转01字符串、加解密等模块实现,伪代码如下: ![]() 全部代码及相关注释点这里github。 2.4 关于密钥的说明起初按如下方式生成64bit密钥,即将密钥中每一个字符转成8bitASCII码,8个字符共构成64bit密钥。 def process_key(key): bin_key = str_bit(key) #调用字符串转01比特流模块 return bin_key结果发现“wuzhenll”和“vt{idomm”这两个密钥加密后的密文相同。 这是因为表面上这两个密码迥然不同,但是由于它们仅在奇偶校验位上有区别。例如,w的ASCII为01110111,v的ASCII为01110110,仅仅只在最后一位有区别。 由于64位密钥中的第8位、第16位、第24位、第32位、第40位、第48位、第56位、第64位作为奇偶校验位,在PC_1置换时去掉了这8位。如果输入的密码只是在这8位上有区别的话,那么操作后的结果也将是一样的。所以用这两个密码进行加密解密操作得到的结果是一样的。 2.5 使用说明运行环境: Python 3.7 使用方法: 将DES_BOX.py、DES.py、以及需要含有明密文的文本文件放置于同一目录下,运行DES.py程序,根据相应提示语即可完成操作。明文加密后乱码会自动保存到text.txt文件中。(注:输入的密钥将转化成对应的ASCII按照偶校验的方式构成64bit初始密钥) 2.6 结果测试测试一:明文:keep early hours! 密钥:password ![]() 测试二: 明文:Have a good day! 密钥:messagee ![]() DES算法原理完整版 DES加解密python实现 DES算法中密钥的校验位 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |